package de.pass.ch.assign;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.HashMap;

import de.pass.ch.pt.IStreetProfile;
import de.pass.ch.util.Constants;
import de.pass.ch.util.Util;

public class AssignmentFactory {

	private String _assignmentFile;

	private HashMap<Integer, Assignment[]> _tmp;

	public AssignmentFactory(String assignmentFile) {

		_assignmentFile = assignmentFile;
		_tmp = new HashMap<Integer, Assignment[]>();

	}

	/**
	 * 
	 * @param id
	 * @param noOfNodes
	 */
	public Assignment[] getAssignments(int id, int noOfNodes,
			IStreetProfile streetProfile, int mode) {

		FileInputStream fIn = null;
		FileChannel channel = null;

		Assignment[] ass = null;

		ass = _tmp.get(id);

		if (ass != null) {
			return ass;
		}

		int bytes = 0;

		try {

			fIn = new FileInputStream(_assignmentFile);
			channel = fIn.getChannel();

			ByteBuffer bb = ByteBuffer.allocate(32).order(ByteOrder.BIG_ENDIAN);
			bb.clear();

			channel.position((id - noOfNodes) * 32);
			bytes += channel.read(bb);
			bb.flip();

			short typ = bb.getShort();
			short factor = bb.getShort();

			bb.order(ByteOrder.LITTLE_ENDIAN);
			int deletedID1 = bb.getInt();
			int assignedID1 = bb.getInt();
			int weight1 = bb.getInt();
			bb.order(ByteOrder.BIG_ENDIAN);
			short direction1 = bb.getShort();

			bb.order(ByteOrder.LITTLE_ENDIAN);
			int deletedID2 = bb.getInt();
			int assignedID2 = bb.getInt();
			int weight2 = bb.getInt();
			bb.order(ByteOrder.BIG_ENDIAN);
			short direction2 = bb.getShort();

			if (mode != Constants.DISTANCE_OPT) {
				weight1 = Util.calculateDuration(weight1, typ, factor,
						streetProfile);
				weight2 = Util.calculateDuration(weight2, typ, factor,
						streetProfile);
			}

			ass = new Assignment[2];

			ass[0] = new Assignment(deletedID1, assignedID1, weight1,
					direction1, factor, typ);
			ass[1] = new Assignment(deletedID2, assignedID2, weight2,
					direction2, factor, typ);

			_tmp.put(id, ass);

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (channel != null)
					channel.close();
				if (fIn != null)
					fIn.close();
			} catch (Exception e) {
			}
		}

		System.out.println(bytes + " bytes read");

		assert (ass != null) : "Fehler beim Assignment-Lesen";

		return ass;
	}

	public void loadAssignments(int[] uss, int[] mapping, int noOfNodes,
			IStreetProfile streetProfile, int mode) {

		System.out.println("load Assignments .....");

		int bytes = 0;

		long start = System.currentTimeMillis();

		FileInputStream fIn = null;
		FileChannel channel = null;

		try {

			fIn = new FileInputStream(_assignmentFile);
			channel = fIn.getChannel();

			ByteBuffer bb = ByteBuffer.allocate(32).order(ByteOrder.BIG_ENDIAN);

			for (int id : uss) {

				if (mapping[id] < noOfNodes)
					continue;

				bb.clear();
				channel = channel.position((mapping[id] - noOfNodes) * 32);
				bytes += channel.read(bb);
				bb.flip();

				short typ = bb.getShort();
				short factor = bb.getShort();

				bb.order(ByteOrder.LITTLE_ENDIAN);
				int deletedID1 = bb.getInt();
				int assignedID1 = bb.getInt();
				int weight1 = bb.getInt();
				bb.order(ByteOrder.BIG_ENDIAN);
				short direction1 = bb.getShort();

				bb.order(ByteOrder.LITTLE_ENDIAN);
				int deletedID2 = bb.getInt();
				int assignedID2 = bb.getInt();
				int weight2 = bb.getInt();
				bb.order(ByteOrder.BIG_ENDIAN);
				short direction2 = bb.getShort();

				if (mode != Constants.DISTANCE_OPT) {
					weight1 = Util.calculateDuration(weight1, typ, factor,
							streetProfile);
					weight2 = Util.calculateDuration(weight2, typ, factor,
							streetProfile);
				}

				Assignment[] ass = new Assignment[2];

				ass[0] = new Assignment(deletedID1, assignedID1, weight1,
						direction1, factor, typ);
				ass[1] = new Assignment(deletedID2, assignedID2, weight2,
						direction2, factor, typ);

				_tmp.put(mapping[id], ass);
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (channel != null)
					channel.close();
				if (fIn != null)
					fIn.close();
			} catch (Exception e) {
			}
		}

		System.out.println(bytes + " bytes read");

		System.out.println("loading Assignments took "
				+ (System.currentTimeMillis() - start) + " ms");

	}
}
